﻿@using Egroo.UI.Components.Layout
@using Egroo.UI.Models
@using Microsoft.AspNetCore.SignalR.Client
@using jihadkhawaja.chat.shared.Interfaces;
@using jihadkhawaja.chat.client.Core;
@using Egroo.UI.Constants
@using System.Text.Json;
@using jihadkhawaja.chat.client.Services;

@inject SessionStorage SessionStorage
@inject StorageService StorageService
@inject NavigationManager NavigationManager
@inject IChatUser ChatUserService
@inject IChatAuth ChatAuthService

@if (IsBusy)
{
    <div style="width:100vw;height:100vh;background-color:var(--mud-palette-background)">
        <MudProgressLinear Indeterminate Color="Color.Primary" />
        <MudText Typo="Typo.h6" Align="Align.Center" Color="Color.Primary" Class="pa-10">
            @GetAppState()
        </MudText>
    </div>
}
else
{
    @ChildContent
}


@code {
    [Inject]
    private ISnackbar Snackbar { get; set; } = null!;

    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    private bool IsBusy { get; set; } = true;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            if (MobileChatSignalR.HubConnection is not null)
            {
                IsBusy = false;
                await InvokeAsync(StateHasChanged);
                return;
            }

            await LoadCache();
            await EstablishSession();

            await SetAppState(AppState.CONNECTED);

            IsBusy = false;
            await InvokeAsync(StateHasChanged);

            PrintStateLog();
        }
    }

    private async Task LoadCache()
    {
        if (!string.IsNullOrWhiteSpace(SessionStorage!.Token))
        {
            return;
        }

        await SetAppState(AppState.LOADING_CACHE);

        switch (ClientModel.CurrentFrameworkPlatform)
        {
            case FrameworkPlatform.MAUI:
                SessionStorage.Token = StorageService.ReadFromJsonFile("token", ClientModel.AppDataPath, true);
                break;
            case FrameworkPlatform.WASM:
            case FrameworkPlatform.SERVER:
                SessionStorage.Token = await StorageService.GetFromLocalStorage("token");
                break;
            default:
                throw new Exception("CurrentFrameworkPlatform parameter is undefined.");
        }
    }

    private async Task EstablishSession()
    {
        MobileChatSignalR.Initialize(Source.HubConnectionURL, SessionStorage?.Token);
        await SetAppState(AppState.ESTABLISHING_CONNECTION);
        await MobileChatSignalR.HubConnection!.StartAsync();

        if (!string.IsNullOrEmpty(SessionStorage!.Token))
        {
            dynamic dynamicObj = await ChatAuthService.RefreshSession(SessionStorage.Token);
            Dictionary<string, object> result = null;
            if (dynamicObj is not null)
            {
                result = JsonSerializer.Deserialize<Dictionary<string, object>>(dynamicObj);
            }
            if (string.IsNullOrWhiteSpace(result["token"].ToString()))
            {
                await SignOut();
                return;
            }

            if (SessionStorage.Token != result["token"].ToString())
            {
                SessionStorage.Token = result["token"].ToString();

                await MobileChatSignalR.HubConnection.StopAsync();
                await MobileChatSignalR.HubConnection.DisposeAsync();

                MobileChatSignalR.Initialize(Source.HubConnectionURL, SessionStorage?.Token);

                if (MobileChatSignalR.HubConnection is null)
                {
                    return;
                }

                SessionStorage!.AppState = AppState.CREATING_SESSION;
                await InvokeAsync(StateHasChanged);

                await MobileChatSignalR.HubConnection.StartAsync();

                switch (ClientModel.CurrentFrameworkPlatform)
                {
                    case FrameworkPlatform.MAUI:
                        StorageService.CreateDirectory(ClientModel.AppDataPath);
                        StorageService.WriteToJsonFile("token", ClientModel.AppDataPath, result["token"].ToString(), false, true);
                        break;
                    case FrameworkPlatform.WASM:
                    case FrameworkPlatform.SERVER:
                        await StorageService.SetLocalStorage("token", result["token"].ToString());
                        break;
                    default:
                        throw new Exception("CurrentFrameworkPlatform parameter is undefined.");
                }
            }

            SessionStorage!.User = new()
            {
                Id = Guid.Parse(result["id"].ToString()),
                Username = await ChatUserService.GetCurrentUserUsername(),
                ConnectionId = MobileChatSignalR.HubConnection.ConnectionId,
            };
        }
    }

    private async Task SetAppState(AppState appState)
    {
        SessionStorage.AppState = appState;
        await InvokeAsync(StateHasChanged);
    }

    private string GetAppState()
    {
        switch (SessionStorage.AppState)
        {
            case AppState.INITIATING:
                return "Initiating";
                case AppState.LOADING_CACHE:
                return "Loading Cache";
                case AppState.ESTABLISHING_CONNECTION:
                return "Establishing Connection";
                case AppState.CREATING_SESSION:
                return "Creating Session";
            case AppState.CONNECTED:
                return "Connected";
            default:
                return "Unknown";
        }
    }

    [JSInvokable]
    public static async Task OnClosedWindow()
    {
        ChatUserService chatUserService = new();
        await chatUserService.CloseUserSession();
    }

    private async Task SignOut()
    {
        switch (ClientModel.CurrentFrameworkPlatform)
        {
            case FrameworkPlatform.MAUI:
                string path = Path.Combine(ClientModel.AppDataPath);
                StorageService.DeleteDirectory(path);
                break;
            case FrameworkPlatform.WASM:
            case FrameworkPlatform.SERVER:
                await StorageService.RemoveFromLocalStorage("token");
                break;
            default:
                throw new Exception("CurrentFrameworkPlatform parameter is undefined.");
        }

        SessionStorage.User = null;

        NavigationManager.NavigateTo("/", true);
    }

    private void PrintStateLog()
    {
#if DEBUG
        Console.WriteLine("\n");
        Console.WriteLine("[State]\t" + SessionStorage.AppState);
        Console.WriteLine("[Framework]\t" + ClientModel.CurrentFrameworkPlatform);
        Console.WriteLine("[Connection Id]\t" + SessionStorage.User?.ConnectionId);
        Console.WriteLine("\n");
#endif
    }
}
